/**
 * tabs - jQuery xui
 *
 * Licensed under the GPL: http://www.gnu.org/licenses/gpl.txt
 *
 * Copyright 2015 xjb [ beymy.en@gmail.com ]
 *
 */
(function($) {

    function init(target) {
        $(target).addClass('tabs').children('div').addClass('tabs-panel').wrapAll('<div class="tabs-panels"></div>');
        $('<div class="tabs-header"><ul class="tabs-nav"></ul></div>').prependTo(target);
        $(target).children('div.tabs-panels').children('div').each(function(i) {
            var opts = $.extend({}, $.parser.parseOptions(this), {
                title: $(this).attr('title')
            });
            createTab(target, opts, $(this));
        });
    }

    function bindEvents(target) {
        var t = $(target);
        var state = $.data(target, 'tabs');
        var opts = state.options;


        $(target).children('div.tabs-header').unbind('.tabs').bind('click.tabs', function(e) {
            var li = $(e.target).closest('li');
            var a = $(e.target).closest('a.tabs-close');
            if (a.length) {
                closeTab(target, getLiIndex(li));
            } else if (li.length) {
                var index = getLiIndex(li);
                var popts = state.tabs[index].data('panel');
                selectTab(target, index);
            }
            return false;
        }).bind('dblclick.tabs', function(e) {
            var li = $(e.target).closest('li');
            var a = li.find('a.tabs-close');
            if (a.length) {
                closeTab(target, getLiIndex(li));
            }
            return false;
        });

        function getLiIndex(li) {
            var index = 0;
            li.parent().children('li').each(function(i) {
                if (li[0] == this) {
                    index = i;
                    return false;
                }
            });
            return index;
        }
    }

    function getTab(target, which) {
        var state = $.data(target, 'tabs');
        var tabs = state.tabs;

        if (typeof which == 'number') {
            if (which < 0 || which >= tabs.length) {
                return null;
            } else {
                return tabs[which];
            }
        } else {
            for (var i = 0; i < tabs.length; i++) {
                var panelOpts = tabs[i].data('panel').options;
                if (panelOpts.title == which) {
                    return tabs[i];
                }
            }
        }

        return null;
    }

    function getTabIndex(target, tab) {
        var tabs = $.data(target, 'tabs').tabs;
        for (var i = 0; i < tabs.length; i++) {
            if (tabs[i] == tab) {
                return i;
            }
        }
        return -1;
    }

    function getSelected(target) {
        var tabs = $.data(target, 'tabs').tabs;
        for (var i = 0; i < tabs.length; i++) {
            var tab = tabs[i];
            if (tab.data('panel').tab.hasClass('tabs-selected')) {
                return tab;
            }
        }
        return null;
    }

    function selectTab(target, which) {
        var state = $.data(target, 'tabs');
        var tabs = state.tabs;
        var opts = state.options;
        var selected = getSelected(target);
        var p = getTab(target, which);
        if (p && !p.is(':visible')) {
            unselectTab(target, getTabIndex(target, selected));

            p.data('panel').tab.addClass('tabs-selected');
            p.show();
            opts.onSelect.call(target, p.data('panel').title, which);
        }
    }

    function unselectTab(target, which) {
        var p = getTab(target, which);
        if (p && p.is(':visible')) {
            p.data('panel').tab.removeClass('tabs-selected');
            p.hide();
        }
    }

    function createTab(target, options, pp) {
        options = options || {};
        var state = $.data(target, 'tabs');
        var tabs = state.tabs;


        if (options.index == undefined || options.index > tabs.length) {
            options.index = tabs.length
        }
        if (options.index < 0) {
            options.index = 0
        }

        var ul = $(target).children('div.tabs-header').find('ul.tabs-nav');
        var panels = $(target).children('div.tabs-panels');

        var tab;
        if (options.closable) {
            tab = $('<li class="tabs-closable">' + options.title + '</li>');
            tab.append('<a class="tabs-close" href="javascript:void(0)"></a>');
        } else {
            tab = $('<li>' + options.title + '</li>');
        }

        if (!pp) {
            pp = $('<div class="tabs-panel"></div>');
        }

        if (options.content) {
            pp.html(options.content);
        }

        pp.data('panel', {
            options: options,
            tab: tab
        });

        if (options.index >= tabs.length) {
            tab.appendTo(ul);
            pp.appendTo(panels);
            tabs.push(pp);
        } else {
            tab.insertBefore(ul.children('li:eq(' + options.index + ')'));
            pp.insertBefore(panels.children('div.tabs-panel:eq(' + options.index + ')'));
            tabs.splice(options.index, 0, pp);
        }

        bindEvents(target);
    }

    function addTab(target, options) {
        var state = $.data(target, 'tabs');
        var opts = state.options;
        if (options.selected == undefined) options.selected = true;

        createTab(target, options);
        if (options.selected) {
            selectTab(target, options.index); // select the added tab panel
        }
    }

    function closeTab(target, which) {
        var t = $(target);
        var state = $.data(target, 'tabs');
        var tabs = state.tabs;

        var tab = getTab(target, which);
        var index = getTabIndex(target, tab);
        var isSelected = tab.data('panel').tab.hasClass('tabs-selected');
        tabs.splice(index, 1);
        tab.data('panel').tab.remove();
        tab.remove();

        if (isSelected) {
            selectTab(target, index < tabs.length ? index : tabs.length - 1);
        }
    }

    $.fn.tabs = function(options, param) {
        if (typeof options == 'string') {
            return $.fn.tabs.methods[options](this, param);
        }

        options = options || {};

        return this.each(function() {
            var state = $.data(this, 'tabs');
            var opts;
            if (state) {
                opts = $.extend(state.options, options);
            } else {
                opts = $.extend({}, $.fn.tabs.defaults, $.fn.tabs.parseOptions(this), options);
                $.data(this, 'tabs', {
                    options: opts,
                    tabs: []
                });
                init(this);
                selectTab(this, 0);
            }

            bindEvents(this);
        });
    };

    $.fn.tabs.methods = {
        options: function(jq) {
            var cc = jq[0];
            var opts = $.data(cc, 'tabs').options;
            var s = getSelectedTab(cc);
            opts.selected = s ? getTabIndex(cc, s) : -1;
            return opts;
        },
        getTab: function(jq, which) {
            return getTab(jq[0], which);
        },
        select: function(jq, which) {
            return jq.each(function() {
                selectTab(this, which);
            });
        },
        add: function(jq, options) {
            return jq.each(function() {
                addTab(this, options);
            });
        },
        close: function(jq, which) {
            return jq.each(function() {
                closeTab(this, which);
            });
        }
    };

    $.fn.tabs.parseOptions = function(target) {
        return $.extend({}, $.parser.parseOptions(target));
    };

    $.fn.tabs.defaults = {
        onSelect: function(title, index) {}
    };
})(jQuery);
